import re
STACK_NUMBER_REGEX = re.compile(r'(.+)(\d+)\+(\d+|\d*\.\d*).*')  # 桩号解析正则式
from functools import total_ordering


class StackNumberWrong(Exception):
    pass


def parse_stack_number(stack_number):
    if stack_number is None:
        raise StackNumberWrong('桩号为None')
    s = STACK_NUMBER_REGEX.match(stack_number)
    if s is None:
        raise StackNumberWrong('桩号无法被解析')
    prefix = s.group(1)
    meters = int(s.group(2)) * 1000 + float(s.group(3))
    return {
        'prefix': prefix,
        'meters': meters
    }


def recreate_stack_number(stack_number, meters):
    prefix = parse_stack_number(stack_number)['prefix']
    return prefix + f'{int(meters/1000)}+{meters%1000}'


@total_ordering
class Stack:
    def __init__(self, stack_number: str, **kwargs):
        self.stack_number = stack_number
        self.parse_stack_number()
        for key, value in kwargs.items():
            if value is not None:
                setattr(self, key, value)

    def __repr__(self):
        return f'Stack("{self.stack_number}")'

    def __str__(self):
        return f'{self.stack_number}'

    def __eq__(self, other):
        return self.meters == other.meters

    def __lt__(self, other):
        return self.meters < other.meters

    def __sub__(self, other):
        return self.meters - other.meters

    def parse_stack_number(self):
        s = parse_stack_number(self.stack_number)
        self.prefix = s['prefix']
        self.meters = s['meters']

    def new_with_offset(self, offset, stack_type='stack', **kwargs):
        stack_number = recreate_stack_number(
            self.stack_number, self.meters+offset)
        stack_classes = {
            'stack': Stack,
            'straight': StraightStack,
            'vertical': VerticalStack,
            'tunnel': TunnelStack,
            'interechange': InterchangeStack
        }
        return stack_classes[stack_type](stack_number, **kwargs)


class StraightStack(Stack):
    type = 'straight'

    def __repr__(self):
        return f'StraightStack("{self.stack_number}")'


class VerticalStack(Stack):
    type = 'vertical'

    def __repr__(self):
        return f'VerticalStack("{self.stack_number}")'


class TunnelStack(Stack):
    type = 'tunnel'

    def __repr__(self):
        return f'TunnelStack("{self.stack_number}")'


class InterchangeStack(Stack):
    type = 'interchange'

    def __repr__(self):
        return f'InterchangeStack("{self.stack_number}")'


class ClearAreaStack(Stack):
    type = 'cleararea'
    width2coefficient = {
        '0.50': 0.88,
        '0.75': 0.93,
        '1.00': 0.97,
        '1.25': 1.00,
        '1.50': 1.02,
        '1.75': 1.04,
        '2.00': 1.06,
        '2.50': 1.09,
        '3.00': 1.11,
        '4.00': 1.15,
        '5.00': 1.17,
        '6.00': 1.20,
        '7.00': 1.22,
        '8.00': 1.23,
        '9.00': 1.25
    }

    def __repr__(self):
        return f'ClearAreaStack("{self.stack_number}")'

    @property
    def influence_coefficient(self):
        return self.width2coefficient['%.2f' % float(self.width)]
